﻿namespace DotRas
{
    using DotRas.Design;
    using pptpclient.Properties;
    using System;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Drawing;
    using System.Security.Permissions;
    using System.Threading;

    [ToolboxItem(true), ToolboxBitmap(typeof(RasConnectionWatcher), "DotRas.RasConnectionWatcher.bmp"), SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
    public sealed class RasConnectionWatcher : RasComponent, ISupportInitialize
    {
        private bool _enableRaisingEvents;
        private RasHandle _handle;
        private bool _initializing;
        private ReadOnlyCollection<RasConnection> _lastState;
        private Collection<RasConnectionWatcherStateObject> _stateObjects;
        private readonly object lockObject;

        [DotRas.SRCategory("CatBehavior"), DotRas.SRDescription("RCWBandwidthAddedDesc")]
        public event EventHandler<EventArgs> BandwidthAdded;

        [DotRas.SRCategory("CatBehavior"), DotRas.SRDescription("RCWBandwidthRemovedDesc")]
        public event EventHandler<EventArgs> BandwidthRemoved;

        [DotRas.SRCategory("CatBehavior"), DotRas.SRDescription("RCWConnectedDesc")]
        public event EventHandler<RasConnectionEventArgs> Connected;

        [DotRas.SRDescription("RCWDisconnectedDesc"), DotRas.SRCategory("CatBehavior")]
        public event EventHandler<RasConnectionEventArgs> Disconnected;

        public RasConnectionWatcher()
        {
            this.lockObject = new object();
            this.InitializeComponent();
        }

        public RasConnectionWatcher(IContainer container) : base(container)
        {
            this.lockObject = new object();
            this.InitializeComponent();
        }

        public void BeginInit()
        {
            bool enableRaisingEvents = this.EnableRaisingEvents;
            this.StopRaisingEvents();
            this.EnableRaisingEvents = enableRaisingEvents;
            this._initializing = true;
        }

        private void ConnectionStateChanged(object obj, bool timedOut)
        {
            lock (this.lockObject)
            {
                ReadOnlyCollection<RasConnection> activeConnections;
                RasConnection connection;
                if (this.EnableRaisingEvents)
                {
                    activeConnections = RasHelper.GetActiveConnections();
                    connection = null;
                    switch (((RasConnectionWatcherStateObject) obj).ChangeType)
                    {
                        case DotRas.NativeMethods.RASCN.Connection:
                            goto Label_0057;

                        case DotRas.NativeMethods.RASCN.Disconnection:
                            goto Label_007C;

                        case DotRas.NativeMethods.RASCN.BandwidthAdded:
                            if ((this.Handle != null) && !this.Handle.IsInvalid)
                            {
                                this.OnBandwidthAdded(EventArgs.Empty);
                            }
                            break;

                        case DotRas.NativeMethods.RASCN.BandwidthRemoved:
                            goto Label_00D2;
                    }
                }
                goto Label_00FE;
            Label_0057:
                connection = FindEntry(activeConnections, this._lastState);
                if (connection != null)
                {
                    this.OnConnected(new RasConnectionEventArgs(connection));
                }
                this._lastState = activeConnections;
                goto Label_00FE;
            Label_007C:
                connection = FindEntry(this._lastState, activeConnections);
                if (connection != null)
                {
                    this.OnDisconnected(new RasConnectionEventArgs(connection));
                }
                if (this.Handle != null)
                {
                    this.Handle = null;
                }
                this._lastState = activeConnections;
                goto Label_00FE;
            Label_00D2:
                if ((this.Handle != null) && !this.Handle.IsInvalid)
                {
                    this.OnBandwidthRemoved(EventArgs.Empty);
                }
            Label_00FE:;
            }
        }

        public void EndInit()
        {
            this._initializing = false;
            if (!this.IsSuspended() && this.EnableRaisingEvents)
            {
                this.StartRaisingEvents();
            }
        }

        private static RasConnection FindEntry(ReadOnlyCollection<RasConnection> collectionA, ReadOnlyCollection<RasConnection> collectionB)
        {
            foreach (RasConnection connection2 in collectionA)
            {
                bool flag = false;
                foreach (RasConnection connection3 in collectionB)
                {
                    if (connection2.EntryId == connection3.EntryId)
                    {
                        flag = true;
                        break;
                    }
                }
                if (!flag)
                {
                    return connection2;
                }
            }
            return null;
        }

        protected override void InitializeComponent()
        {
            this._stateObjects = new Collection<RasConnectionWatcherStateObject>();
            base.InitializeComponent();
        }

        private bool IsSuspended()
        {
            bool designMode = true;
            if (!this._initializing)
            {
                designMode = base.DesignMode;
            }
            return designMode;
        }

        private void OnBandwidthAdded(EventArgs e)
        {
            base.RaiseEvent<EventArgs>(this.BandwidthAdded, e);
        }

        private void OnBandwidthRemoved(EventArgs e)
        {
            base.RaiseEvent<EventArgs>(this.BandwidthRemoved, e);
        }

        private void OnConnected(RasConnectionEventArgs e)
        {
            base.RaiseEvent<RasConnectionEventArgs>(this.Connected, e);
        }

        private void OnDisconnected(RasConnectionEventArgs e)
        {
            base.RaiseEvent<RasConnectionEventArgs>(this.Disconnected, e);
        }

        [SecurityPermission(SecurityAction.Demand, Flags=SecurityPermissionFlag.UnmanagedCode)]
        private void Register(DotRas.NativeMethods.RASCN changeType, RasHandle handle)
        {
            AutoResetEvent waitObject = new AutoResetEvent(false);
            if (DotRas.SafeNativeMethods.RasConnectionNotification(handle, waitObject.SafeWaitHandle, changeType) == 0)
            {
                RasConnectionWatcherStateObject obj2;
                obj2 = new RasConnectionWatcherStateObject(changeType) {
                    WaitObject = waitObject,
                    WaitHandle = ThreadPool.RegisterWaitForSingleObject(waitObject, new WaitOrTimerCallback(this.ConnectionStateChanged), obj2, -1, false)
                };
                this._stateObjects.Add(obj2);
            }
        }

        private void Restart()
        {
            if (!this.IsSuspended() && this.EnableRaisingEvents)
            {
                this.StopRaisingEvents();
                this.StartRaisingEvents();
            }
        }

        private void StartRaisingEvents()
        {
            this._lastState = RasHelper.GetActiveConnections();
            try
            {
                this.Register(DotRas.NativeMethods.RASCN.Connection, DotRas.NativeMethods.INVALID_HANDLE_VALUE);
                if ((this.Handle == null) || this.Handle.IsInvalid)
                {
                    this.Register(DotRas.NativeMethods.RASCN.Disconnection, DotRas.NativeMethods.INVALID_HANDLE_VALUE);
                }
                else
                {
                    this.Register(DotRas.NativeMethods.RASCN.Disconnection, this.Handle);
                    this.Register(DotRas.NativeMethods.RASCN.BandwidthAdded, this.Handle);
                    this.Register(DotRas.NativeMethods.RASCN.BandwidthRemoved, this.Handle);
                }
            }
            catch (EntryPointNotFoundException)
            {
                DotRas.ThrowHelper.ThrowNotSupportedException(Resources.Exception_NotSupportedOnPlatform);
            }
        }

        private void StopRaisingEvents()
        {
            if (!this.IsSuspended() && this.EnableRaisingEvents)
            {
                int count = this._stateObjects.Count;
                for (int i = 0; i < count; i++)
                {
                    RasConnectionWatcherStateObject item = this._stateObjects[0];
                    if (item != null)
                    {
                        this.Unregister(item);
                    }
                }
            }
        }

        private void Unregister(RasConnectionWatcherStateObject item)
        {
            if (item != null)
            {
                item.WaitHandle.Unregister(item.WaitObject);
                item.WaitObject.Close();
                this._stateObjects.Remove(item);
            }
        }

        [DotRas.SRCategory("CatBehavior"), DotRas.SRDescription("RCWEnableRaisingEventsDesc"), DefaultValue(false)]
        public bool EnableRaisingEvents
        {
            get
            {
                return this._enableRaisingEvents;
            }
            set
            {
                if (this._enableRaisingEvents != value)
                {
                    this._enableRaisingEvents = value;
                    if (!this.IsSuspended())
                    {
                        if (this._enableRaisingEvents)
                        {
                            this.StartRaisingEvents();
                        }
                        else
                        {
                            this.StopRaisingEvents();
                        }
                    }
                }
            }
        }

        [Browsable(false)]
        public RasHandle Handle
        {
            get
            {
                return this._handle;
            }
            set
            {
                if ((value != null) && Utilities.IsHandleInvalidOrClosed(value))
                {
                    DotRas.ThrowHelper.ThrowInvalidHandleException(value, Resources.Exception_InvalidOrClosedHandle);
                }
                if (this._handle != value)
                {
                    this._handle = value;
                    this.Restart();
                }
            }
        }

        private sealed class RasConnectionWatcherStateObject
        {
            private DotRas.NativeMethods.RASCN _changeType;
            private RegisteredWaitHandle _waitHandle;
            private AutoResetEvent _waitObject;

            public RasConnectionWatcherStateObject(DotRas.NativeMethods.RASCN changeType)
            {
                this._changeType = changeType;
            }

            public DotRas.NativeMethods.RASCN ChangeType
            {
                get
                {
                    return this._changeType;
                }
            }

            public RegisteredWaitHandle WaitHandle
            {
                get
                {
                    return this._waitHandle;
                }
                set
                {
                    this._waitHandle = value;
                }
            }

            public AutoResetEvent WaitObject
            {
                get
                {
                    return this._waitObject;
                }
                set
                {
                    this._waitObject = value;
                }
            }
        }
    }
}

